package com.jinke.game;

import com.jinke.tank.EnemyTank;
import com.jinke.tank.MyTank;
import com.jinke.tank.Tank;
import com.jinke.util.ExplosionPool;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import static com.jinke.util.Constant.*;

/**
 * 游戏窗体类
 */
public class GameFrame extends JFrame implements Runnable{

    public static JPanel gamePanel;
    MyTank mytank;

    /**
     * 游戏状态
     * 取值范围: MENU_START, MENU_CONTINUE, MENU_HELP, MENU_ABOUT, MENU_EXIT(0-4)
     */
    public static int gameState;

    /**
     * 当前选中的菜单索引
     */
    private int menuIndex;
    //敌人坦克
    List<Tank> enemyTanks = new ArrayList<>();

    /**
     * 创建游戏窗体
     */
    public GameFrame() {


        initFrame();
        initPanel();
        initEventListener();
        // 确保所有组件初始化完成后再进行焦点,初始化游戏和线程设置,避免在窗口完全初始化前初始化游戏和启动线程
        SwingUtilities.invokeLater(() -> {
            if (gamePanel != null) {
                initGame();
                gamePanel.requestFocusInWindow();
                gamePanel.grabFocus();
            }
            new Thread(this).start();
        } );

    }

    /**
     * 初始化窗体
     */
    private void initFrame() {
        this.setTitle(GAME_TITLE);
        this.setSize(GAME_WIDTH, GAME_HEIGHT);
        this.setLocationRelativeTo(null);//居中
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭为退出
        this.setResizable(false);//不可改变窗体大小
        this.setVisible(true);
    }

    /**
     * 初始化面板
     */
    private void initPanel() {
        gamePanel = new JPanel(){
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setFont(MENU_FONT);
                switch (gameState){
                    case STATE_MENU:
                        drawMenu(g);
                        break;
                    case STATE_RUN:
                        drawRun(g);
                        break;
                    case STATE_HELP:
                        drawHelp(g);
                        break;
                    case STATE_ABOUT:
                        drawAbout(g);
                        break;
                    case STATE_OVER:
                        drawOver(g);
                        break;
                }
            }
        };

        gamePanel.setFocusable(true);//设置panel可获取焦点
        gamePanel.setFocusTraversalKeysEnabled(false); // 禁用焦点遍历键
        gamePanel.enableInputMethods(false);

        this.add(gamePanel);
    }

    /**
     * 初始化游戏
     */
    private void initGame() {
        gameState = STATE_MENU;
    }


    private void drawOver(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
        g.setColor(Color.WHITE);
        g.drawString("游戏结束", GAME_WIDTH / 2 - 50, GAME_HEIGHT / 2);
        g.setColor(Color.WHITE);
        g.drawString("按回车键重新开始游戏", GAME_WIDTH / 2 - 100, GAME_HEIGHT / 2 + 30);
        g.drawString("按Esc键退回菜单", GAME_WIDTH / 2 - 100, GAME_HEIGHT / 2 + 60);
    }

    private void drawAbout(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
        g.setColor(Color.WHITE);
        final int STR_WIDTH = g.getFontMetrics().stringWidth("作者: 孙金科");
        int x = (GAME_WIDTH - STR_WIDTH) / 2;
        //菜单项的Y坐标
        int y = GAME_HEIGHT / 5;
        final int LINE_HEIGHT = 50;
        g.drawString("关于游戏", x, y);
        g.drawString("作者: 孙金科", x, y+LINE_HEIGHT);
        g.drawString("特别鸣谢:", x, y+2*LINE_HEIGHT);
        g.drawString("刘智元", x, y+3*LINE_HEIGHT);
        g.drawString("吴奕霏", x, y+4*LINE_HEIGHT);
        g.drawString("路源远", x, y+5*LINE_HEIGHT);
        g.drawString("阿桃", x, y+6*LINE_HEIGHT);
    }

    private void drawHelp(Graphics g) {
    }

    private void drawRun(Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
        drawEnemy(g);
        mytank.drawTank(g);
        bulletCollideTank();
        // 更新所有爆炸动画
        ExplosionPool.instance.drawAll(g);
    }

    /**
     * 绘制敌人
     */
    private void drawEnemy(Graphics g) {
        for (int i = 0; i < enemyTanks.size(); i++) {
            Tank tank = enemyTanks.get(i);
            if (tank.getState() == Tank.STATE_DEAD) {
                enemyTanks.remove(i);
                i--;
                continue;
            }
            tank.drawTank(g);
        }
    }

    /**
     * 绘制菜单
     * @param g 系统提供的画笔,用于绘制窗口内容
     */
    private void drawMenu(Graphics g) {
        //绘制黑色背景
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
        //绘制菜单
        g.setColor(Color.WHITE);
        //菜单项的X坐标(计算字体宽度来达到居中的效果)
        final int STR_WIDTH = g.getFontMetrics().stringWidth(MENU_ITEMS[0]);
        int x = (GAME_WIDTH - STR_WIDTH) / 2;
        //菜单项的Y坐标
        int y = GAME_HEIGHT / 3;
        final int LINE_HEIGHT = 50;
        for (int i = 0; i < MENU_ITEMS.length; i++) {
            if (i == menuIndex) {
                g.setColor(Color.RED);
            }else  {
                g.setColor(Color.WHITE);
            }
            g.drawString(MENU_ITEMS[i], x, y + i * LINE_HEIGHT);
        }
    }

    /**
     * 初始化事件监听器
     */
    private void initEventListener() {
        gamePanel.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int keyCode = e.getKeyCode();
                switch (gameState){
                    case STATE_MENU:
                        keyPressedEventMenu(keyCode);
                        break;
                    case STATE_RUN:
                        keyPressedEventRun(keyCode);
                        break;
                    case STATE_HELP:
                        break;
                    case STATE_ABOUT:
                        keyPressedEventAbout(keyCode);
                        break;
                    case STATE_OVER:
                        keyPressedEventOver(keyCode);

                        break;
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                int keyCode = e.getKeyCode();
                if (gameState == STATE_RUN){
                        keyReleasedEventRun(keyCode);
                }
            }
        });
    }

    private void keyPressedEventOver(int keyCode) {
        switch (keyCode){
            case KeyEvent.VK_ENTER:
                newGame();
                break;
            case KeyEvent.VK_ESCAPE:
                gameState = STATE_MENU;
        }
    }

    private void keyPressedEventAbout(int keyCode) {
        switch (keyCode){
            case KeyEvent.VK_ESCAPE:
                gameState = STATE_MENU;
                initGame();
                gamePanel.requestFocusInWindow();
                gamePanel.grabFocus();
                gamePanel.repaint();
                break;
        }
    }

    private void keyReleasedEventRun(int keyCode) {
        boolean changed = false;
        switch (keyCode){
            case KeyEvent.VK_UP:
            case KeyEvent.VK_W:
                mytank.keyStates[Tank.DIR_UP] = false;
                changed = true;
                break;
            case KeyEvent.VK_DOWN:
            case KeyEvent.VK_S:
                mytank.keyStates[Tank.DIR_DOWN] = false;
                changed = true;
                break;
            case KeyEvent.VK_LEFT:
            case KeyEvent.VK_A:
                mytank.keyStates[Tank.DIR_LEFT] = false;
                changed = true;
                break;
            case KeyEvent.VK_RIGHT:
            case KeyEvent.VK_D:
                mytank.keyStates[Tank.DIR_RIGHT] = false;
                changed = true;
                break;
        }
        if (changed){
            mytank.updateMoveState();
        }
    }

    private void keyPressedEventRun(int keyCode) {
        boolean changed = false;
        switch (keyCode){
            case KeyEvent.VK_UP:
            case KeyEvent.VK_W:
//                mytank.setDir(Tank.DIR_UP);//旧版的方式,会产生停顿问题
//                mytank.setState(Tank.STATE_MOVE);
                mytank.keyStates[Tank.DIR_UP] = true;//新版方式,用键状态数组来记录按键状态,避免了停顿问题
                changed = true;//但有可能会使玩家操作上感觉有些怪(不过应该没有逆天同时按两个以上的按键……)
                break;
            case KeyEvent.VK_DOWN:
            case KeyEvent.VK_S:
//                mytank.setDir(Tank.DIR_DOWN);
//                mytank.setState(Tank.STATE_MOVE);
                mytank.keyStates[Tank.DIR_DOWN] = true;
                changed = true;
                break;
            case KeyEvent.VK_LEFT:
            case KeyEvent.VK_A:
//                mytank.setDir(Tank.DIR_LEFT);
//                mytank.setState(Tank.STATE_MOVE);
                mytank.keyStates[Tank.DIR_LEFT] = true;
                changed = true;
                break;
            case KeyEvent.VK_RIGHT:
            case KeyEvent.VK_D:
//                mytank.setDir(Tank.DIR_RIGHT);
//                mytank.setState(Tank.STATE_MOVE);
                mytank.keyStates[Tank.DIR_RIGHT] = true;
                changed = true;
                break;
            case KeyEvent.VK_J:
                mytank.fire(mytank);
                break;
            case KeyEvent.VK_ESCAPE:
                gameState = STATE_MENU;
                gamePanel.requestFocusInWindow();
                gamePanel.grabFocus();
                gamePanel.repaint();
                break;
        }
        if (changed){
            mytank.updateMoveState();
        }
    }

    private void keyPressedEventMenu(int keyCode) {
        switch (keyCode){
            case KeyEvent.VK_UP:
            case KeyEvent.VK_W:
                if (--menuIndex < 0){
                    menuIndex = MENU_ITEMS.length - 1;
                }
//                gamePanel.repaint();//非多线程绘制
                break;
            case KeyEvent.VK_DOWN:
            case KeyEvent.VK_S:
                if (++menuIndex >= MENU_ITEMS.length){
                    menuIndex = 0;
                }
//                gamePanel.repaint();//非多线程绘制
                break;
            case KeyEvent.VK_ENTER:
                switch (menuIndex){
                    case 0:
                        newGame();
                        break;
                    case 1:
                        break;
                    case 2:
                        break;
                    case 3:
                        gameState = STATE_ABOUT;
                        break;
                    case 4:
                        System.exit(0);
                        break;
                }
                break;
        }
    }

    /**
     * 开始新游戏的方法
     */
    public void newGame(){
        gameState = STATE_RUN;
        mytank = new MyTank(100, 100, Tank.DIR_DOWN,gamePanel.getWidth(), gamePanel.getHeight());
        new Thread(() -> {
            while (true) {
                if (enemyTanks.size() < MAX_ENEMY_COUNT){
                    Tank enemyTank = EnemyTank.createEnemyTank();
                    enemyTanks.add(enemyTank);
                }
                try {
                    Thread.sleep(ENEMY_SPAWN_INTERVAL);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }

    @Override
    public void run() {
        //专门启动一个线程来实现重绘功能
        while (true){
            gamePanel.repaint();
            try {
                Thread.sleep(REPAINT_INTERVAL);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private void bulletCollideTank(){
        for (Tank enemyTank : enemyTanks){
            enemyTank.collisionCheck(mytank.getBullets());
        }
        for (Tank enemyTank : enemyTanks){
            mytank.collisionCheck(enemyTank.getBullets());
        }
    }
}
